﻿using System;
using System.Linq;

using Buddy.BehaviorTree;
using Buddy.Common;
using Buddy.CommonBot;
using Buddy.Swtor;
using Buddy.Swtor.Objects;

using WingIt;
using WingIt.Dynamics;
using WingIt.Routines.Mirrors;

using Action = Buddy.BehaviorTree.Action;

namespace WingIt.Routines
{
    [RevisionControlId("$Id: Vengeance_Vigilance.cs 688 2012-08-13 09:16:20Z Chinajade $")]
    public class JuggernautVengeance_GuardianVigilance : MirrorRoutine
    {
        // MAINTAINERS NOTES:
        // * You will notice that lambda expression argument names are unique (e.g., "darkWardOn", "darkWardWhen", "joltWhen"),
        //   instead of generic (e.g., "ctx", "ret", "on", "doWhen", "castWhen").  PLEASE honor this convention!
        //   This allows us to quickly localize problems when looking at user's logs.  When the BehaviorTree encounters an exception
        //   (e.g., "object not found"), the location where an exception is thrown is identifiable only through the name
        //   of the lambda expression argument.  Such is the nature of BehaviorTrees.

        [Behavior(BehaviorType.Pull)]
        [Class(CharacterClass.Warrior, AdvancedClass.Juggernaut, SkillTreeId.JuggernautVengeance)]
        [Class(CharacterClass.Knight, AdvancedClass.Guardian, SkillTreeId.GuardianVigilance)]
        public static Composite JuggernautVengeance_GuardianVigilance_Pull()
        {
            return new PrioritySelector(
                // Gates
                LazyRaider.CreateBTPS_NotifyAndShortCircuitWhenCombatDisabled(),
                CreateBTPS.BWcoreFixup_WaitForHarvestComplete(),
                TargetSelect.CreateBTPS_UpdateForBattlefieldConditions(),

                // Prep
                //CreateBTPS.BWcoreFixup_Dismount(),
                CreateBTPS.ApplyGuard(applyGuardWhen => Me.HasMirrorBuff("Soresu Form")),

                // Engage
                JuggernautVengeance_GuardianVigilance_Combat()
                );
        }

        [Behavior(BehaviorType.Combat)]
        [Class(CharacterClass.Warrior, AdvancedClass.Juggernaut, SkillTreeId.JuggernautVengeance)]
        [Class(CharacterClass.Knight, AdvancedClass.Guardian, SkillTreeId.GuardianVigilance)]
        public static Composite JuggernautVengeance_GuardianVigilance_Combat()
        {
            return new PrioritySelector(
                LazyRaider.CreateBTPS_NotifyAndShortCircuitWhenCombatDisabled(),
                TargetSelect.CreateBTPS_UpdateForBattlefieldConditions(),

                CreateBTPS.StopWithinRangeAndLoS(target => MyTarget, Global.Distance.Melee),
              
                //***General***
                Cast("Saber Throw", saberThrowWhen => MyTarget.IsInRange(3f, 0.5f)),
                Cast("Force Charge", forceChargeWhen => MyTarget.IsInRange(3f, 1f) && !MyTarget.IsCoverAffected), //+3 Rage/15s CD/30m Range - Pull
                Cast("Force Push", forcePushWhen => MyTarget.Toughness == CombatToughness.Player),
                Cast("Unleash", unleashWhen => Me.IsStunned),//Insignia/2m CD
                Cast("Enrage", enrageWhen => Me.ResourceStat <= 6),//+6 Rage

                //**Interrupt**
                // NB: These are ordered by reach of the ability (shortest reach interrupt-ability first).  This is so we don't burn
                // a far-reaching interrupt on a target that is standing next to us.
                Cast("Disruption", disruptionOn => InterruptTarget, disruptionWhen => TargetSelect.ForInterrupt(c => c.IsInRange(0.4f)) != null),//4m
                Cast("Backhand", backhandOn => InterruptTarget, backhandWhen => (((TargetSelect.ForInterrupt(c => c.IsInRange(0.4f)) != null) && (!Me.CanMirrorCast("Force Choke", MyTarget) && !Me.CanMirrorCast("Disruption", MyTarget)) || Me.HealthPercent <= 30)) && !Me.HasMirrorBuff("Saber Ward")),//4m
                Cast("Force Choke", forceChokeOn => InterruptTarget, forceChokeWhen => (TargetSelect.ForInterrupt(c => c.IsInRange(1f)) != null) || (Me.HealthPercent <= 30 && !Me.HasMirrorBuff("Saber Ward"))),//10m

                //**CC**
                new Decorator(crowdControlWhen => (CCTarget != null) && (Me.MobCountAround(0.5f) >= 3) && (Me.MobCountAttacking() >= 3),
                    new PrioritySelector(
                        //Cast("Chilling Scream", chillingScreamOn => CCTarget, chillingScreamWhen => Me.ResourceStat >= 3),
                        Cast("Intimidating Roar", intimidatingRoarOn => CCTarget, intimidatingRoarWhen => Me.HealthPercent <= 60)
                        )),

                //**Defensive**
                BuffSelf("Endure Pain", endurePainWhen => Me.HealthPercent <= 30),
                BuffSelf("Saber Ward", saberWardWhen => Me.HealthPercent <= 50),//3m CD   

                //**Heal**
                Cast("Intercede", intercedeOn => HealTarget, intercedeWhen => TargetSelect.ForHeal(true, c => c.HealthPercent <= Global.Health.Mid) != null),//30m

                //**Offensive**
                Cast("Vicious Throw", viciousThrowWhen => MyTarget.HealthPercent <= 20 && Me.ResourceStat >= 3),//-3 Rage
                Cast("Pommel Strike", pommelStrikeWhen => MyTarget.IsStunned && (MyTarget.Toughness == CombatToughness.Standard || MyTarget.Toughness == CombatToughness.Weak)),//strong skill but only usable on stunned - normal or weak - enemys
                Cast("Savage Kick", savageKickWhen => MyTarget.Toughness != CombatToughness.Player),
                new Decorator(reduceArmorWhen => !MyTarget.HasMirrorDebuffStacks("Armor Reduced", 5, d => (d.TimeLeft >= TimeSpan.FromSeconds(2))) || Me.ResourceStat <= 9,
                    new PrioritySelector(
                        Cast("Sundering Assault"))),
                Cast("Shatter", shatterWhen => MyTarget.HasMirrorDebuff("Sundering Assault")),
                Cast("Impale"),
                Cast("Force Scream", forceScreamWhen => 
                {
                    if (Me.ResourceStat >= 4 || (Me.HasMirrorAbility("Battle Cry") && Me.HasMirrorBuff("Battle Cry")))
                        { return Me.HasImpliedMirrorBuff("Savagery"); }
                    return false;
                }),
                Cast("Backhand", backhandWhen => Me.ResourceStat >= 3 && !MyTarget.IsStunned),
                Cast("Smash", smashWhen => (Me.MobCountAround(Global.Distance.Melee) >= 2 && Me.MobCountAttacking() >= 2) || Me.HasMirrorAbility("Ruin")),//-3 Rage/15s CD
                Cast("Sweeping Slash", sweepingSlashWhen => Me.MobCountAround(0.5f) >= 4  && Me.MobCountAttacking() >= 4),//-3 Rage/15s CD
                Cast("Ravage"),
                Cast("Vicious Slash"),
                Cast("Assault"),

                // We may be mounted (and no Companion out) at the pull.  So, we have to wait until combat to try to apply guard.
                CreateBTPS.ApplyGuard(applyGuardWhen => Me.HasMirrorBuff("Soresu Form")),

                //Movement
                CreateBTPS.MoveWithinRangeAndLoS(target => MyTarget, Global.Distance.Melee)
                );
        }

        [Behavior(BehaviorType.OutOfCombat)]
        [Class(CharacterClass.Warrior, AdvancedClass.Juggernaut, SkillTreeId.JuggernautVengeance)]
        [Class(CharacterClass.Knight, AdvancedClass.Guardian, SkillTreeId.GuardianVigilance)]
        public static Composite JuggernautVengeance_GuardianVigilance_OutOfCombat()
        {
            // NB: Apparently, BWcore will call this routine when in combat on occasion.  It is also called while we're pulling.
            return (new PrioritySelector(
                TargetSelect.CreateBTPS_UpdateForBattlefieldConditions(),
                new Decorator(oocBuffWhen => !Me.IsMounted,
                    new PrioritySelector(
                        BuffSelf("Shien Form"),
                        BuffSelf("Shii-Cho Form", shiiChoFormWhen => !Me.HasMirrorAbility("Shien Form")),
                        CreateBTPS.ApplyGuard(applyGuardWhen => Me.HasMirrorBuff("Soresu Form"))
                        ))
             ));
        }
    }
}
